package lib

import (
	"fmt"
	"github.com/cihub/seelog"
	ffmpeg "github.com/u2takey/ffmpeg-go"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"sync"
)

// Function to get the duration of a video using ffmpeg
func GetVideoDuration(filePath string) (int64, error) {
	// Use ffprobe to get video metadata
	cmd := exec.Command("ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", filePath)
	out, err := cmd.Output()
	if err != nil {
		return 0, fmt.Errorf("failed to execute ffprobe command: %v", err)
	}

	res := strings.Split(string(out), ".")[0]
	seelog.Infof("video duration %s", res)

	// Convert duration to float64
	duration, err := strconv.ParseInt(res, 10, 64)
	if err != nil {
		return 0, fmt.Errorf("invalid duration format: %v", err)
	}

	return duration, nil
}

func GetSplit(filePath, output string, start, end int64) error {
	if start == 0 {
		durationStr := fmt.Sprintf("%d", end-start)
		err := ffmpeg.Input(filePath).Output(output, ffmpeg.KwArgs{"t": durationStr, "c": "copy"}).OverWriteOutput().Run()
		if err != nil {
			seelog.Errorf("failed to split start part: %v", err)
			return err
		}
	} else if end == -1 {
		durationStr := fmt.Sprintf("%d", start)
		err := ffmpeg.Input(filePath, ffmpeg.KwArgs{"ss": durationStr}).Output(output, ffmpeg.KwArgs{"c": "copy"}).OverWriteOutput().Run()
		if err != nil {
			seelog.Errorf("failed to split end part: %v", err)
			return err
		}
	} else {
		startStr := fmt.Sprintf("%d", start)
		endStr := fmt.Sprintf("%d", end)
		err := ffmpeg.Input(filePath, ffmpeg.KwArgs{"ss": startStr, "to": endStr}).Output(output, ffmpeg.KwArgs{"c": "copy"}).OverWriteOutput().Run()
		if err != nil {
			seelog.Errorf("failed to split middle part: %v", err)
			return err
		}
	}

	return nil
}

func GetSplitPart(filePath string, duration int64) error {

	halfDuration := duration / 2
	halfDurationStr := fmt.Sprintf("%.2f", halfDuration)

	// First part
	output1 := "/root/data/detect_track/video/part1.mp4"
	err := ffmpeg.Input(filePath).Output(output1, ffmpeg.KwArgs{"t": halfDurationStr, "c": "copy"}).Run()
	if err != nil {
		seelog.Errorf("failed to split first part: %v", err)
		return err
	}

	return nil
}

func GetSplitOtherPart(filePath string, duration int64) error {
	halfDuration := duration / 2
	halfDurationStr := fmt.Sprintf("%.2f", halfDuration)

	// Second part
	output2 := "/root/data/detect_track/video/part2.mp4"
	err := ffmpeg.Input(filePath, ffmpeg.KwArgs{"ss": halfDurationStr}).Output(output2, ffmpeg.KwArgs{"c": "copy"}).Run()
	if err != nil {
		seelog.Errorf("failed to split second part: %v", err)
	}

	return nil
}

// Function to split the video into two equal parts
func SplitVideo(filePath string, duration float64) error {
	halfDuration := duration / 2
	halfDurationStr := fmt.Sprintf("%.2f", halfDuration)

	wg := sync.WaitGroup{}

	wg.Add(1)
	go func() {
		defer wg.Done()
		// First part
		output1 := "/root/data/detect_track/video/part1.mp4"
		err := ffmpeg.Input(filePath).Output(output1, ffmpeg.KwArgs{"t": halfDurationStr, "c": "copy"}).Run()
		if err != nil {
			seelog.Errorf("failed to split first part: %v", err)
		}
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		// Second part
		output2 := "/root/data/detect_track/video/part2.mp4"
		err := ffmpeg.Input(filePath, ffmpeg.KwArgs{"ss": halfDurationStr}).Output(output2, ffmpeg.KwArgs{"c": "copy"}).Run()
		if err != nil {
			seelog.Errorf("failed to split second part: %v", err)
		}
	}()

	wg.Wait()
	return nil
}

// Function to create a temporary file list for FFmpeg
func createFileList(filePaths []string) (string, error) {
	tmpFile, err := os.CreateTemp("", "ffmpeg_file_list_*.txt")
	if err != nil {
		return "", fmt.Errorf("failed to create temporary file: %v", err)
	}

	for _, filePath := range filePaths {
		_, err := tmpFile.WriteString(fmt.Sprintf("file '%s'\n", filePath))
		if err != nil {
			tmpFile.Close()
			return "", fmt.Errorf("failed to write to temporary file: %v", err)
		}
	}

	err = tmpFile.Close()
	if err != nil {
		return "", fmt.Errorf("failed to close temporary file: %v", err)
	}

	return tmpFile.Name(), nil
}

// Function to merge videos using ffmpeg
func MergeVideos(outputPath string, filePaths []string) error {
	// Create a temporary file list
	fileList, err := createFileList(filePaths)
	if err != nil {
		return err
	}
	defer os.Remove(fileList) // Clean up the temporary file after use

	// Run the ffmpeg command to concatenate the videos
	cmd := ffmpeg.Input(fileList, ffmpeg.KwArgs{"f": "concat", "safe": "0"}).
		Output(outputPath, ffmpeg.KwArgs{"c": "copy"}).Compile()

	if cmd == nil {
		return fmt.Errorf("failed to create ffmpeg command")
	}

	// Execute the command
	out, err := exec.Command(cmd.Path, cmd.Args[1:]...).CombinedOutput()
	if err != nil {
		return fmt.Errorf("ffmpeg command failed: %v, output: %s", err, string(out))
	}

	return nil
}

func ConvertToH264(inputFile string, outputFile string) error {
	// 构造 FFmpeg 命令
	cmd := exec.Command("ffmpeg", "-i", inputFile, "-c:v", "libx264", outputFile)

	// 运行命令并捕获输出
	if err := cmd.Run(); err != nil {
		seelog.Errorf("ffmpeg command failed: %v", err)
		return fmt.Errorf("failed to convert video: %w", err)
	}

	return nil
}
